//******************************************************************************/
// There are many implementations of glWindow, using glut, SDL, wxWidgets, QT.
//
// This is the FreeGLUT Version.
//
//(c) 2003-2006 by Martin Christen. All Rights reserved.
//******************************************************************************/

#include <GL/glew.h>
#include <GL/freeglut.h>
#include "glutWindow.h"
#include <iostream>

using namespace cwc;

//-----------------------------------------------------------------------------

// Optimizacion, es lento usar una lista de stl, mas rapido es un vector
//std::list<glutWindow*> glutWindow::_gWinInstances;

glutWindow * glutWindow::_gWinInstances[MAX_GLWINDOW_INSTANCES];
bool glutWindow::_bLMouseDown;
unsigned int glutWindow::_cantGlWindowInstances = 0;
//-----------------------------------------------------------------------------

glutWindow::glutWindow(unsigned int width, unsigned int height) {
	_bLMouseDown = false;
	//_gWinInstances.push_back(this);

	// Inicializo el vector si soy el primero
	if (_cantGlWindowInstances == 0) {
		for (int i = 0; i < MAX_GLWINDOW_INSTANCES; i++) {
			_gWinInstances[i] = NULL;
		}
	}

	//-------------------------------------------
	this->width = width;
	this->height = height;
	glutInitWindowSize(this->width, this->height);
	glutInitWindowPosition(100, 100);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	//--------------------------------------------

	if (_cantGlWindowInstances == MAX_GLWINDOW_INSTANCES) {
	}

	_gWindow = glutCreateWindow("66.71 Sistemas Graficos - UBA / 2013");
	_bInit = false;

	if (_gWinInstances[_gWindow] != NULL) {
	}
	_gWinInstances[_gWindow] = this;

	std::cout << "Glut Window " << _gWindow << std::endl;

	glutDisplayFunc(sDisplay);
	glutReshapeFunc(sReshape);
	glutMouseFunc(sMouse);
	glutMotionFunc(sMotion);
//#ifdef FREEGLUT
	glutMouseWheelFunc(sMouseWheel);
	glutCloseFunc(sClose);
	glutPassiveMotionFunc(sPassiveMotion);
//#endif   
	glutKeyboardFunc(sKeyDown);
	glutSpecialFunc(sSpecialDown);
	glutKeyboardUpFunc(sKeyUp);
	glutSpecialUpFunc(sSpecialUp);
	glutIdleFunc(sIdle);
}

//-----------------------------------------------------------------------------

glutWindow::~glutWindow(void) {

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if (*i == this) {
	 _gWinInstances.erase(i);
	 return;
	 }

	 i++;
	 }*/
	this->_gWinInstances[this->_gWindow] = NULL;
	glutDestroyWindow(this->_gWindow);
}

//-----------------------------------------------------------------------------

void glutWindow::sClose(void) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnClose();

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnClose();
	 //delete (*i);
	 return;
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sReshape(int w, int h) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnResize(w, h);

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnResize(w, h);
	 }

	 i++;
	 }*/

}

//-----------------------------------------------------------------------------

void glutWindow::sDisplay(void) {
	int CurrentWindow = glutGetWindow();

	if (!_gWinInstances[CurrentWindow]->_bInit) {
		_gWinInstances[CurrentWindow]->OnInit();
		_gWinInstances[CurrentWindow]->_bInit = true;
	}
	_gWinInstances[CurrentWindow]->OnRender();
	/*
	 std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if (!(*i)->_bInit) {
	 (*i)->OnInit();
	 (*i)->_bInit = true;
	 }

	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnRender();
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sMouse(int button, int updown, int x, int y) {
	int CurrentWindow = glutGetWindow();

	if (updown) {
		if (button == 0)
			_bLMouseDown = false;
		_gWinInstances[CurrentWindow]->OnMouseUp(button, x, y);
	} else {
		if (button == 0)
			_bLMouseDown = true;
		_gWinInstances[CurrentWindow]->OnMouseDown(button, x, y);
	}

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 if (updown) {
	 if (button == 0)
	 _bLMouseDown = false;
	 (*i)->OnMouseUp(button, x, y);
	 } else {
	 if (button == 0)
	 _bLMouseDown = true;
	 (*i)->OnMouseDown(button, x, y);
	 }
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sMotion(int x, int y) {
	int CurrentWindow = glutGetWindow();

	if (_bLMouseDown)
		_gWinInstances[CurrentWindow]->OnLeftMouseDrag(x, y);

	_gWinInstances[CurrentWindow]->OnMouseMove(x, y);

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 if (_bLMouseDown)
	 (*i)->OnLeftMouseDrag(x, y);

	 (*i)->OnMouseMove(x, y);
	 }

	 i++;
	 }*/
}

void glutWindow::sPassiveMotion(int x, int y) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnMouseMove(x, y);
	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnMouseMove(x, y);
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sMouseWheel(int wheel_number, int direction, int x, int y) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnMouseWheel(wheel_number, direction, x, y);

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnMouseWheel(wheel_number, direction, x, y);
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sJoystick(unsigned int a, int b, int c, int d) {
}

//-----------------------------------------------------------------------------

void glutWindow::sSpecialUp(int key, int x, int y) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnKeyUp(key, 0);

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnKeyUp(key, 0);
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sKeyUp(unsigned char key, int x, int y) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnKeyUp(0, key);

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnKeyUp(0, key);
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sSpecialDown(int key, int x, int y) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnKeyDown(key, 0);

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnKeyDown(key, 0);
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sKeyDown(unsigned char key, int x, int y) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnKeyDown(0, key);

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnKeyDown(0, key);
	 }

	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::sIdle(void) {
	int CurrentWindow = glutGetWindow();

	_gWinInstances[CurrentWindow]->OnIdle();

	/*std::list<glutWindow*>::iterator i = _gWinInstances.begin();

	 while (i != _gWinInstances.end()) {
	 if ((*i)->_gWindow == CurrentWindow) {
	 (*i)->OnIdle();
	 }
	 i++;
	 }*/
}

//-----------------------------------------------------------------------------

void glutWindow::Repaint() {
	glutPostWindowRedisplay(_gWindow);
}

//-----------------------------------------------------------------------------

void glutWindow::SetFullscreen(bool bFullscreen) {
	if (bFullscreen) {
		glutFullScreen();
	} else {
		int w = 640; //glutGet(GLUT_WINDOW_WIDTH);
		int h = 480; //glutGet(GLUT_WINDOW_HEIGHT);
		int x = 0; //glutGet(GLUT_WINDOW_X);
		int y = 0; //glutGet(GLUT_WINDOW_Y);

		glutPositionWindow(x, y);
		glutReshapeWindow(w, h);
	}
}

void glutWindow::SetSize(int width, int height) {

	glutReshapeWindow(width, height);
	this->width = width;
	this->height = height;
}

//-----------------------------------------------------------------------------

void glutWindow::Hide() {
	glutHideWindow();
}

//-----------------------------------------------------------------------------

void glutWindow::Show() {
	glutShowWindow();
}

//-----------------------------------------------------------------------------   

void glutWindow::Close() {
	glutDestroyWindow(_gWindow);
}

//-----------------------------------------------------------------------------
